package com.sinog.biz.util;

import com.sinog.biz.BizApplication;
import com.sinog.biz.config.ProvinceCodes2Config;
import com.sinog.biz.config.ProvinceCodes3Config;
import com.sinog.core.domain.PrisonerCjpg;
import com.sinog.core.domain.PrisonerFx;
import com.sinog.core.domain.PrisonerJxjs;
import com.sinog.core.domain.PrisonerMain;
import com.sinog.core.domain.PrisonerSr;
import com.sinog.core.domain.PrisonerZn;
import com.sinog.core.model.PrisonerXixxVo;
import com.sinog.core.model.xml.HnAjxxVo;
import com.sinog.core.model.xml.HnMessageVo;
import com.sinog.core.util.CollectionUtils;
import com.sinog.core.util.DateUtil;
import com.sinog.core.util.IdNumUtil;
import com.sinog.core.util.PhoneUtil;
import com.sinog.core.util.StrUtil;
import com.sinog.core.utilbean.Constants;
import com.sinog.core.utilbean.HnStyleReturnCode;
import com.sinog.core.utilbean.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @desc 湖南看守所对接Util
 * @author wangxj
 * @date 2022/6/29 下午3:31
 */
@Configuration
public class CheckUtil {

    /**
     * checkParams中对应VALUE属性,校验value
     */
    private static final String VALUE = "VALUE";
    /**
     * checkParams中对应IS_NULL属性,属性为空提示信息
     */
    private static final String ISNULL = "IS_NULL";
    /**
     * checkParams中对应IS_MAST属性,字段是否必填
     */
    private static final String ISMAST = "IS_MAST";
    /**
     * checkParams中对应TYPE属性,1:查字典,2:用户输入,4:日期类型,5:身份证信息,6:电话号码,7:手机号码,8:身份证
     */
    private static final String TYPE = "TYPE";
    /**
     * checkParams中对应IS_ERROR属性,属性错误提示
     */
    private static final String ISERROR = "IS_ERROR";
    /**
     * checkParams中对应MAX_LENGTH属性,字段最大长度
     */
    private static final String INDEXOUTOFF = "MAX_LENGTH";
    /**
     * transferParams中中对应POVALUE属性,将xml中传输的key转换为数据库对应的真实字段
     */
    private static final String POVALUE = "POVALUE";
    /**
     * transferParams中对应FIELDTYPE属性,反射为对象赋值时属性的类型,String,Integer,Date
     */
    private static final String FIELDTYPE = "FIELDTYPE";
    /**
     * 反射调用provinceCodes2Config类获取方法
     */
    private static final String METHODNAME1 = "provinceCodes2Config";
    /**
     * 反射调用provinceCodes3Config类获取方法
     */
    private static final String METHODNAME2 = "provinceCodes3Config";

    /**
     * 参数校验
     * @param paramMap 请求传输的map
     * @return Result 异常信息返回
     */
    public Result checkParams(Map<String,List<Map<String, String>>> paramMap) {
        // 1、迭代paramMap,为参数校验
        for(String next : paramMap.keySet()) {
            // processType为流程节点,不进行校验
            if("processType".equals(next)) {
                continue;
            }
            // 2、反射获取provinceCodes2Config属性
            Map<String,Map<String,String>> resultMap = this.getDeclaredMethod(next,METHODNAME1);
            // 3、获取paramMap集合中的数据,例如:基本信息,服刑信息,社会关系信息,子女信息
            List<Map<String,String>> listMap = paramMap.get(next);
            for(Map<String,String> map1 : listMap) {
                // 4、循环迭代传输字段信息
                for(String next1 : map1.keySet()) {
                    // 5、获取xml中传输的值
                    String value = map1.get(next1);
                    // 6、获取checkParams.yml文件中当前属性配置内容
                    Map<String,String> map = resultMap.get(next1);
                    if(null == map) {
                        continue;
                    }
                    // 属性是否必填
                    boolean flag1 = Constants.NumberStr.NUM_STR_ONE.equals(map.get(ISMAST));
                    // 非空检查
                    boolean notBlank = StringUtils.isNotBlank(value);
                    String type = map.get(TYPE);
                    // 获取属性能接受的最大长度
                    String maxLength = map.get(INDEXOUTOFF);
                    int length = 0;
                    if(null != maxLength) {
                        length = Integer.parseInt(maxLength);
                    }
                    // 字段是否非空
                    if(flag1 && StringUtils.isBlank(value)) {
                        return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISNULL))));
                    }
                    // 查询字段是否超出最大长度
                    if(0 != length && length < value.length()) {
                        return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                    }
                    // 需要查询字典
                    if(flag1 && Constants.NumberStr.NUM_STR_ONE.equals(type) && !StrUtil.stringContainsEquals(value,map.get(VALUE))) {
                        return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                    }
                    if(notBlank){
                        // 时间类型检查
                        if(Constants.NumberStr.NUM_STR_FOUR.equals(type) && DateUtil.checkStrDate(value)) {
                            return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                            // 身份证校验
                        } else if(Constants.NumberStr.NUM_STR_EIGHT.equals(type) && IdNumUtil.checkIdNum(value)) {
                            return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                            // 电话号码校验
                        } else if(Constants.NumberStr.NUM_STR_SIX.equals(type) && !PhoneUtil.phone(value)) {
                            return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                            // 手机号校验
                        } else if(Constants.NumberStr.NUM_STR_SEVEN.equals(type) && !PhoneUtil.isMobile(value)) {
                            return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                            // 手机号码|电话校验
                        } else if(Constants.NumberStr.NUM_STR_NINE.equals(type) && (!PhoneUtil.isMobile(value) && !PhoneUtil.phone(value))) {
                            return Result.failure(HnStyleReturnCode.getTypeMsg(Integer.parseInt(map.get(ISERROR))));
                        }
                    }
                }
            }
        }
        return Result.success();
    }

    /**
     * 参数组装
     * @param paramMap 请求传输的map
     * @param processType processType
     * @return Result
     */
    public Result asscessParams(Map<String,List<Map<String, String>>> paramMap,String processType) throws Exception {
        Map<String,Object> returnMap = new HashMap<>(16);
        PrisonerMain prisonerMain = null;
        PrisonerFx prisonerFx = null;
        PrisonerCjpg prisonerCjpg = null;
        PrisonerXixxVo prisonerXjxx = null;
        PrisonerSr[] srs = {};
        PrisonerZn[] zns = {};
        PrisonerJxjs[] jxjs = {};
        HnMessageVo hnMessage = null;
        HnAjxxVo hnAjxx = null;
        // 根据流程节点创建对象
        if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_A.equals(processType)) {
            prisonerMain = new PrisonerMain();
            prisonerFx = new PrisonerFx();
            if(CollectionUtils.isNotEmpty(paramMap.get("SHGX"))) {
                srs = new PrisonerSr[paramMap.get("SHGX").size()];
            }
            if(CollectionUtils.isNotEmpty(paramMap.get("ZNXX"))) {
                zns = new PrisonerZn[paramMap.get("ZNXX").size()];
            }
            hnMessage = new HnMessageVo();
            hnAjxx = new HnAjxxVo();
        } else if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_C.equals(processType)){
            prisonerCjpg = new PrisonerCjpg();
            prisonerXjxx = new PrisonerXixxVo();
            prisonerFx = new PrisonerFx();
            if(CollectionUtils.isNotEmpty(paramMap.get("JXJS"))) {
                jxjs = new PrisonerJxjs[paramMap.get("JXJS").size()];
            }
            hnMessage = new HnMessageVo();
        } else if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_D.equals(processType)){
            prisonerMain = new PrisonerMain();
            prisonerXjxx = new PrisonerXixxVo();
            hnMessage = new HnMessageVo();
        }
        int i = 0;
        int j = 0;
        int jn = 0;
        int js = 0;
        for(String next : paramMap.keySet()) {
            if("processType".equals(next)) {
                continue;
            }
            // 反射获取provinceCodes3Config方法
            Map<String,Map<String,String>> resultMap = this.getDeclaredMethod(next,METHODNAME2);
            List<Map<String,String>> listMap = paramMap.get(next);
            if("SHGX".equals(next)) {
                for(int k = 0; k < listMap.size(); k++) {
                    srs[k] = new PrisonerSr();
                }
            }
            if("ZNXX".equals(next)) {
                for(int k = 0; k < listMap.size(); k++) {
                    zns[k] = new PrisonerZn();
                }
            }
            if("JXJS".equals(next)) {
                for(int k = 0; k < listMap.size(); k++) {
                    jxjs[k] = new PrisonerJxjs();
                }
            }
            // map1: 基本信息,服刑信息...
            for(Map<String,String> map1 : listMap) {
                // 遍历map1中所有属性
                for(String next1 : map1.keySet()) {
                    // 获取属性名称
                    // 获取属性值
                    String value = map1.get(next1);
                    String value1 = "";
                    String fieldType = "";
                    String value2 = "";
                    if(null != resultMap && !resultMap.isEmpty()) {
                        // 获取transferParams中属性配置信息
                        Map<String,String> map = resultMap.get(next1);
                        if(null == map) {
                            continue;
                        }
                        // transferParams中对应po属性
                        value1 = map.get(POVALUE);
                        // transferParams中对应FIELDTYPE属性,反射为对象赋值时属性的类型,String,Integer,Date
                        fieldType = map.get(FIELDTYPE);
                        // transferParams中对应的安置帮教的字典值
                        value2 = map.get(value);
                    }
                    // 参数赋值
                    if("JBXX".equals(next)) {
                        Field[] field = prisonerMain.getClass().getDeclaredFields();
                        // field:属性字段,prisonerMain:表,FIELDTYPE:属性类型,value1:属性值,value2:安置帮教的字典值
                        prisonerMain = this.setFieldValue(field,prisonerMain,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                        if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_D.equals(processType)) {
                            Field[] fieldXj = prisonerXjxx.getClass().getDeclaredFields();
                            prisonerXjxx = this.setFieldValue(fieldXj,prisonerXjxx,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                        }
                    } else if("FXXX".equals(next)) {
                        Field[] field = prisonerFx.getClass().getDeclaredFields();
                        prisonerFx = this.setFieldValue(field,prisonerFx,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("CJPG".equals(next)) {
                        Field[] field = prisonerCjpg.getClass().getDeclaredFields();
                        prisonerCjpg = this.setFieldValue(field,prisonerCjpg,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                        //服刑信息
                        Field[] fxField = prisonerFx.getClass().getDeclaredFields();
                        prisonerFx = this.setFieldValue(fxField,prisonerFx,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("FQXJ".equals(next)) {
                        //发起衔接
                        Field[] field = prisonerXjxx.getClass().getDeclaredFields();
                        prisonerXjxx = this.setFieldValue(field,prisonerXjxx,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("JXJS".equals(next)) {
                        Field[] field = jxjs[js].getClass().getDeclaredFields();
                        jxjs[js] = this.setFieldValue(field,jxjs[js],fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("SHGX".equals(next)) {
                        Field[] field = srs[i].getClass().getDeclaredFields();
                        srs[i] = this.setFieldValue(field,srs[i],fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("ZNXX".equals(next)) {
                        Field[] field = zns[j].getClass().getDeclaredFields();
                        zns[j] = this.setFieldValue(field,zns[j],fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("MESSAGE".equals(next)) {
                        Field[] fxField = hnMessage.getClass().getDeclaredFields();
                        hnMessage = this.setFieldValue(fxField,hnMessage,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    } else if("AJXX".equals(next)) {
                        Field[] fxField = hnAjxx.getClass().getDeclaredFields();
                        hnAjxx = this.setFieldValue(fxField,hnAjxx,fieldType,value1,StringUtils.isBlank(value2) ? value : value2);
                    }
                }
                if("SHGX".equals(next)) {
                    i++;
                }
                if("ZNXX".equals(next)) {
                    j++;
                }
                if("ZYJN".equals(next)) {
                    jn++;
                }
                if("JXJS".equals(next)) {
                    js++;
                }
            }
        }
        if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_A.equals(processType)) {
            returnMap.put("PrisonerMain",prisonerMain);
            returnMap.put("prisonerFx",prisonerFx);
            returnMap.put("prisonerSr",srs);
            returnMap.put("prisonerZn",zns);
            returnMap.put("hnMessage",hnMessage);
            returnMap.put("hnAjxx",hnAjxx);
        } else if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_C.equals(processType)){
            returnMap.put("cjpg",prisonerCjpg);
            returnMap.put("jxjs",jxjs);
            returnMap.put("cjpgFx",prisonerFx);
            returnMap.put("hnMessage",hnMessage);
        }else if(Constants.HnInterfaceDocking.ZERO_SEVEN_ZERO_TWO_D.equals(processType)){
            returnMap.put("fqxj",prisonerXjxx);
            returnMap.put("hnMessage",hnMessage);
        }
        return Result.success(returnMap);
    }

    /**
     * 反射调用对象的属性
     * @param paramKey 属性key
     * @param beanName Spring对象bean名称
     * @return Map<String,Map<String,String>>
     */
    public Map<String,Map<String,String>> getDeclaredMethod(String paramKey, String beanName){
        ApplicationContext applicationContext = BizApplication.applicationContext;
        Object bean = applicationContext.getBean(beanName);
        Map<String,Map<String,String>> map = new HashMap<>(32);
        Method declaredMethod;
        if(bean instanceof ProvinceCodes2Config) {
            ProvinceCodes2Config provinceCodes2Config = (ProvinceCodes2Config) bean;
            Class<ProvinceCodes2Config> provinceCodes2ConfigClass = ProvinceCodes2Config.class;
            try {
                declaredMethod = provinceCodes2ConfigClass.getDeclaredMethod("get" + paramKey);
                declaredMethod.setAccessible(true);
                map = (Map<String, Map<String, String>>) declaredMethod.invoke(provinceCodes2Config,null);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        } else if(bean instanceof ProvinceCodes3Config){
            ProvinceCodes3Config provinceCodes3Config = (ProvinceCodes3Config) bean;
            Class<ProvinceCodes3Config> provinceCodes3ConfigClass = ProvinceCodes3Config.class;
            try {
                declaredMethod = provinceCodes3ConfigClass.getDeclaredMethod("getTS" + paramKey);
                declaredMethod.setAccessible(true);
                map = (Map<String, Map<String, String>>) declaredMethod.invoke(provinceCodes3Config,null);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    /**
     * 反射为对象赋值
     * @param field 属性值
     * @param t po对象
     * @param fieldType 属性类型
     * @param value1 属性字段
     * @param value 安置帮教的字典值
     * @return T 返回对象
     */
    public <T> T setFieldValue(Field[] field, T t,String fieldType,String value1,String value) throws Exception{
        // 循环遍历属性为对象赋值
        for(Field item : field) {
            String name = item.getName();
            name = name.substring(0,1).toUpperCase() + name.substring(1);
            Method n = null;
            if(!StringUtils.isBlank(value) && fieldType.equals(Constants.NumberStr.NUM_STR_ONE) && value1.equalsIgnoreCase(name)) {
                n = t.getClass().getMethod("set" + name,String.class);
            } else if(!StringUtils.isBlank(value) && fieldType.equals(Constants.NumberStr.NUM_STR_TWO) && value1.equalsIgnoreCase(name)) {
                n = t.getClass().getMethod("set" + name,Integer.class);
            } else if(!StringUtils.isBlank(value) && fieldType.equals(Constants.NumberStr.NUM_STR_THREE) && value1.equalsIgnoreCase(name)) {
                n = t.getClass().getMethod("set" + name,Date.class);
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                n.invoke(t,simpleDateFormat.parse(value));
                continue;
            }
            if(null != n) {
                // 反射执行
                n.invoke(t,value);
                return t;
            }
        }
        return t;
    }
}